package j.framework.core;

import j.framework.annotation.ConnectionType;
import j.framework.annotation.Service;
import j.framework.annotation.ServiceMethod;
import j.util.SpringBeans;
import j.util.StringUtils;
import j.util.jdbc.JdbcTemplate;
import j.util.jdbc.QueryJdbcTemplate;
import j.util.jdbc.TransactionalJdbcTemplate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 业务层类的动态代理，此类的操作根据ServiceMethod注解完成相关调用前及后的处理
 * User: jason
 * Date: 2014/11/10 10:47
 */
public class ServiceProxy implements InvocationHandler {

    private static final Log log = LogFactory.getLog(ServiceProxy.class);

    private Object target;

    private MembershipProvider membershipProvider;

    /**
     * 模块ID，用来检测登录人是否具备此模块权限
     */
    private String functionId;
    private String functionName;

    private JdbcTemplate jdbcTemplate;

    /**
     * 绑定委托对象
     * @param target
     * @return 代理对象
     */
    public Object bind(Object target) {
        //获取用户身份提供器
        membershipProvider = FApplication.getMembershipProvider();
        Service service = target.getClass().getAnnotation(Service.class);
        jdbcTemplate = SpringBeans.getBean(JdbcTemplate.class);
        if(service!=null){
            functionId = service.functionId();
            functionName = service.displayName();
        }
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result=null;
        JdbcTemplate jt = jdbcTemplate;
        log.debug("业务层"+functionName+"("+target.getClass().getName()+")的方法"+method.getName()+"开始调用");
        try {
            //调用前执行的方法
            //先获取当前操作上下文
            ServiceContext context = (ServiceContext) args[0];
            if(StringUtils.isNotEmpty(functionId)){
                if(!membershipProvider.hasFunction(context.getUser(),functionId)){
                    context.actionResult.add("您没有此【"+functionName+"】模块的权限！");
                    return null;
                }
            }
            ServiceMethod serviceMethod = method.getAnnotation(ServiceMethod.class);
            boolean logSupported = false;
            if (serviceMethod != null) {
                logSupported = serviceMethod.logSupported();
                if(!membershipProvider.hasAction(context.getUser(),functionId,serviceMethod.actionId())){
                    context.actionResult.add("您没有此【"+functionName+"】模块的["+serviceMethod.displayName()+"]权限！");
                    return null;
                }
                if(!logSupported) {
                    if (serviceMethod.connectionType().equals(ConnectionType.QUERY)) {
                        jt = new QueryJdbcTemplate(jdbcTemplate.getDataSource());
                    } else if (serviceMethod.connectionType().equals(ConnectionType.TRANSACTIONAL)) {
                        jt = new TransactionalJdbcTemplate(jdbcTemplate.getDataSource(), true);
                    }
                }
            }
            context.setJdbcTemplate(jt);

            result = method.invoke(target, args);
            //调用后执行的方法
            log.debug("业务层"+functionName+"("+target.getClass().getName()+")的方法"+method.getName()+"结束调用");
            return result;
        }catch (Exception e){
            jt.rollback();
            log.debug("业务层"+functionName+"("+target.getClass().getName()+")的方法"+method.getName()+"调用时出错，异常："+e.getMessage());
            throw new RuntimeException("执行业务["+target.getClass().getName()+"]方法["+method.getName()+"]时出错，异常信息："+e.getMessage());
        }finally {
            jt.close();
        }
    }
}
